package jmine.tec.utils.collection.impl;

import java.io.Serializable;
import java.util.AbstractMap;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.ObjectUtils;

/**
 * Implementacao de {@link Map} que permite apenas um elemento (que deve ser passado no construtor)
 * 
 * @author takeshi
 * @param <K> o tipo da chave
 * @param <V> o tipo do valor
 */
public class SingletonMap<K, V> extends AbstractMap<K, V> implements Map<K, V>, Serializable {

    private final K thisKey;

    private final V thisValue;

    /**
     * Metodo factory para criar um singletonMap
     * 
     * @param <K> o tipo da chave
     * @param <V> o tipo do valor
     * @param key a chave
     * @param value o valor
     * @return {@link Map}
     */
    public static <K, V> Map<K, V> singletonMap(K key, V value) {
        return new SingletonMap<K, V>(key, value);
    }

    /**
     * Construtor
     * 
     * @param key a chave
     * @param value o valor a ser associado
     */
    public SingletonMap(K key, V value) {
        this.thisKey = key;
        this.thisValue = value;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int size() {
        return 1;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean containsKey(Object key) {
        return ObjectUtils.equals(key, this.thisKey);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean containsValue(Object value) {
        return ObjectUtils.equals(value, this.thisValue);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public V get(Object key) {
        if (this.containsKey(key)) {
            return thisValue;
        }
        return null;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isEmpty() {
        return false;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Set<K> keySet() {
        return Collections.singleton(this.thisKey);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Collection<V> values() {
        return Collections.singleton(this.thisValue);
    }

    private Entry<K, V> entry = new Entry<K, V>() {

        public K getKey() {
            return thisKey;
        }

        public V getValue() {
            return thisValue;
        }

        public V setValue(V value) {
            throw new UnsupportedOperationException();
        }
    };

    /**
     * {@inheritDoc}
     */
    @Override
    public Set<Entry<K, V>> entrySet() {
        return Collections.singleton(this.entry);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void clear() {
        throw new UnsupportedOperationException();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public V put(K key, V value) {
        throw new UnsupportedOperationException();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void putAll(Map<? extends K, ? extends V> m) {
        throw new UnsupportedOperationException();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public V remove(Object key) {
        throw new UnsupportedOperationException();
    }

}
